package jmine.tec.hydra.web.pages.requisicao;

import static jmine.tec.web.wicket.pages.form.WebFormPagesMessages.ERROR_CANNOT_FIND_ENTITY_TO_VIEW;

import java.io.Serializable;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import jmine.tec.hydra.HydraController;
import jmine.tec.hydra.dao.HydraRequestDAO;
import jmine.tec.hydra.domain.HydraRequestImpl;
import jmine.tec.hydra.domain.HydraSystem;
import jmine.tec.hydra.domain.StatusHydraRequest;
import jmine.tec.hydra.domain.enumx.HydraRequestType;
import jmine.tec.report.impl.ReportBuilder;
import jmine.tec.report.impl.table.ReportTableBuilder;
import jmine.tec.rtm.impl.web.pages.ConsultaDetalheExceptionRecord;
import jmine.tec.web.pages.HelpTextMessages;
import jmine.tec.web.wicket.component.autocomplete.NaturalKeyAutocomplete;
import jmine.tec.web.wicket.component.command.img.ImageCommand;
import jmine.tec.web.wicket.component.command.img.PageLinkImageCommand;
import jmine.tec.web.wicket.component.command.img.ViewCommand;
import jmine.tec.web.wicket.component.command.img.ViewCommandHandler;
import jmine.tec.web.wicket.converter.TimestampConverter;
import jmine.tec.web.wicket.pages.form.ListPage;

import org.apache.wicket.Page;
import org.apache.wicket.PageParameters;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.spring.injection.annot.SpringBean;

import bancosys.tec.exception.BusinessException;
import bancosys.tec.exception.MessageCreator;
import bancosys.tec.persist.dao.BaseDAOFactory;
import bancosys.tec.persist.dao.BeanNotFoundException;
import bancosys.tec.security.annotation.Secure;
import bancosys.tec.security.authorization.UrlPermission;
import bancosys.tec.utils.date.Date;
import bancosys.tec.utils.date.Timestamp;

/**
 * Tela de consulta das requisições feitas ao hydra.
 * 
 * @author finx
 * @created Nov 6, 2010
 */
@Secure(id = "URL_LIST_INTEGRACAO_REQUISICAO", permissionType = UrlPermission.class)
public class ConsultaIntegracaoRequisicao extends ListPage<HydraRequestImpl, HydraRequestImpl> implements ViewCommandHandler {

    @SpringBean(name = "hydraController")
    private HydraController hydraController;

    private Date startDate = new Date();

    private Date finalDate = new Date();

    private String horarioStart;

    private String horarioEnd;

    private StatusHydraRequest statusHydraRequest;

    private HydraRequestType hydraRequestType;

    private HydraSystem hydraSystem;

    /**
     * Construtor.
     */
    public ConsultaIntegracaoRequisicao() {
        super();
    }

    /**
     * Construtor.
     * 
     * @param pageParameters {@link PageParameters}
     */
    public ConsultaIntegracaoRequisicao(PageParameters pageParameters) {
        super(pageParameters);
    }

    /**
     * {@inheritDoc}
     */
    public List<HydraRequestImpl> search(BaseDAOFactory daoFactory) {
        Timestamp tsStart = this.getTimestampByDateAndTime(this.startDate, this.horarioStart);
        Timestamp tsEnd = this.getTimestampByDateAndTime(this.finalDate, this.horarioEnd);
        if ((this.horarioEnd == null) || this.horarioEnd.equals("")) {
            tsEnd.addDays(1);
        }
        HydraRequestDAO dao = this.hydraController.getDAOFactory().getDAOByClass(HydraRequestDAO.class);
        return dao.findByPeriodoStatusTipoSistema(tsStart, tsEnd, this.statusHydraRequest, this.hydraRequestType, this.hydraSystem);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected HydraRequestImpl createModel() {
        return this.getHydraRequestDAO().createBean();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void addSearchFields(WebMarkupContainer container) {
        container.add(this.createDateField("dataInicial", new PropertyModel<Date>(this, "startDate"), true));
        container.add(this.createDateField("dataFinal", new PropertyModel<Date>(this, "finalDate"), true));
        container.add(this.createTextField("horarioStart", new PropertyModel<String>(this, "horarioStart")));
        container.add(this.createTextField("horarioEnd", new PropertyModel<String>(this, "horarioEnd")));
        container.add(this.createDropDown("status", new PropertyModel<StatusHydraRequest>(this, "statusHydraRequest"),
                Arrays.asList(StatusHydraRequest.values()), true));
        container.add(this.createDropDown("requestType", new PropertyModel<HydraRequestType>(this, "hydraRequestType"),
                Arrays.asList(HydraRequestType.values()), true));
        NaturalKeyAutocomplete<HydraSystem> hydraSystemAutoComplete =
                new NaturalKeyAutocomplete<HydraSystem>(HydraSystem.class, "hydraSystem");
        hydraSystemAutoComplete.setModel(new PropertyModel<HydraSystem>(this, "hydraSystem"));
        container.add(hydraSystemAutoComplete);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void addResultTableColumns(ReportTableBuilder<HydraRequestImpl> table) {
        table.addStringColumn("identificador", "Identificador", "id");
        table.addStringColumn("sistema", "Sistema", "system");
        table.addStringColumn("tipoRequisicao", "Tipo Requisição", "requestType");
        table.addTimestampColumn("inicioRequisicao", "Inicio da Requisição", "requestStart");
        table.addTimestampColumn("fimRequisicao", "Final da Requisição", "requestEnd");
        table.addStringColumn("status", "Status", "status");
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected MessageCreator getHelpTextCreator() {
        return HelpTextMessages.CONSULTA_INTEGRACAO_REQUISICAO;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean shouldIncludeTableCommands() {
        return true;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected List<ImageCommand> getTableCommands(HydraRequestImpl hydraRequestImpl) {
        List<ImageCommand> commands = new ArrayList<ImageCommand>();
        commands.add(new ViewCommand(this));

        if (hydraRequestImpl.getExceptionRecord() != null) {
            ConsultaDetalheExceptionRecord page = new ConsultaDetalheExceptionRecord(this.getPage(), hydraRequestImpl.getExceptionRecord());
            commands.add(new PageLinkImageCommand(page, "file.png"));
        }
        return commands;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void addReportHeader(ReportBuilder reportBuilder) {
        reportBuilder.addHeaderDateParameter("dataInicial", "Data Inicial", this.startDate);
        reportBuilder.addHeaderDateParameter("dataFinal", "Data Final", this.finalDate);
        this.addHeaderStringParameter(reportBuilder, "horarioStart", "Hora Inicial", this.horarioStart);
        this.addHeaderStringParameter(reportBuilder, "horarioEnd", "Hora Final", this.horarioEnd);
        this.addHeaderStringParameter(reportBuilder, "sistema", "Sistema", this.hydraSystem);
        this.addHeaderStringParameter(reportBuilder, "status", "Status", this.statusHydraRequest);
        this.addHeaderStringParameter(reportBuilder, "tipoRequisicao", "Tipo Requisição", this.statusHydraRequest);
    }

    /**
     * Adiciona o objeto informado ao header do {@link ReportBuilder} caso o mesmo não seja nulo.
     * 
     * @param reportBuilder {@link ReportBuilder}.
     * @param id id da propriedade.
     * @param label label que será exibido no report
     * @param object objeto que será exibido no cabeçalho.
     */
    private void addHeaderStringParameter(ReportBuilder reportBuilder, String id, String label, Object object) {
        if (object != null) {
            reportBuilder.addHeaderStringParameter(id, label, object.toString());
        }
    }

    /**
     * {@inheritDoc}
     */
    public Page createViewPage(Serializable entityPk) {
        try {
            HydraRequestImpl request = this.loadEntity(entityPk);
            return new ConsultaDetalheIntegracaoRequisicao(request.getId(), this.getPage());
        } catch (BeanNotFoundException e) {
            throw new BusinessException(ERROR_CANNOT_FIND_ENTITY_TO_VIEW.create(this.getPageName(), entityPk));
        }
    }

    /**
     * Cria um Timestamp a partir da data e horário passados nos parâmetros.
     * 
     * @param data a data
     * @param time o horário (formato "HH:mm")
     * @return um Timestamp criado a partir da data e horário passados nos parâmetros.
     */
    private Timestamp getTimestampByDateAndTime(Date data, String time) {
        String timeToParse = (time == null) || time.equals("") ? "00:00:00" : time + ":00";
        DateFormat dataFormat = new SimpleDateFormat("dd/MM/yyyy");
        Timestamp ts = (Timestamp) new TimestampConverter().convertToObject(dataFormat.format(data) + " " + timeToParse, null);
        ts.setNanos(0);
        return ts;
    }

    /**
     * @return the startDate
     */
    public Date getStartDate() {
        return this.startDate;
    }

    /**
     * @param startDate the startDate to set
     */
    public void setStartDate(Date startDate) {
        this.startDate = startDate;
    }

    /**
     * @return the finalDate
     */
    public Date getFinalDate() {
        return this.finalDate;
    }

    /**
     * @param finalDate the finalDate to set
     */
    public void setFinalDate(Date finalDate) {
        this.finalDate = finalDate;
    }

    /**
     * @return the horarioStart
     */
    public String getHorarioStart() {
        return this.horarioStart;
    }

    /**
     * @param horarioStart the horarioStart to set
     */
    public void setHorarioStart(String horarioStart) {
        this.horarioStart = horarioStart;
    }

    /**
     * @return the horarioEnd
     */
    public String getHorarioEnd() {
        return this.horarioEnd;
    }

    /**
     * @param horarioEnd the horarioEnd to set
     */
    public void setHorarioEnd(String horarioEnd) {
        this.horarioEnd = horarioEnd;
    }

    /**
     * @return {@link HydraRequestDAO}
     */
    private HydraRequestDAO getHydraRequestDAO() {
        return this.hydraController.getDAOFactory().getDAOByClass(HydraRequestDAO.class);
    }
}
